package com.pentalog.fullsix.bean;

import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

import javax.faces.application.Application;
import javax.faces.context.FacesContext;
import javax.faces.context.Flash;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.collections.comparators.NullComparator;
import org.apache.commons.collections.comparators.ReverseComparator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.jsf.FacesContextUtils;


/**
 * The Class BaseBean.
 */

public abstract class BaseBean implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * Log variable for all child classes.
	 */
	protected final Logger logger = LoggerFactory.getLogger(getClass());

	/** The theme. */
	private String theme = "redmond"; // default

	/** The application context. */
	protected ApplicationContext applicationContext = FacesContextUtils.getRequiredWebApplicationContext(FacesContext.getCurrentInstance());
	

	/** The faces context. */
	protected FacesContext facesContext;

	/** The sort column. */
	protected String sortColumn;

	/** The ascending. */
	protected Boolean ascending;

	/** The nulls are high. */
	protected boolean nullsAreHigh;

	public Object getManagedBean(String beanName) {
		return getApplication().evaluateExpressionGet(getFacesContext(), "#{" + beanName + "}", Object.class);
	}
	public static Flash flashScope (){
		Flash flash =FacesContext.getCurrentInstance().getExternalContext().getFlash(); 
		flash.setKeepMessages(true); 
		
		return flash;
	}

	public Application getApplication() {
		return getFacesContext().getApplication();
	}

	/**
	 * Gets the faces context.
	 * 
	 * @return the faces context
	 */
	public FacesContext getFacesContext() {
		return FacesContext.getCurrentInstance();
	}

	// Convenience methods ====================================================
	/**
	 * Gets the parameter.
	 * 
	 * @param name
	 *            the name
	 * @return the parameter
	 */
	public String getParameter(final String name) {
		return getRequest().getParameter(name);
	}

	/**
	 * Gets the bundle name.
	 * 
	 * @return the bundle name
	 */
	public String getBundleName() {
		return getFacesContext().getApplication().getMessageBundle();
	}
	
	/**
	 * Gets the bundle.
	 * 
	 * @return the bundle
	 */
	public ResourceBundle getBundle() {
		final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		return ResourceBundle.getBundle(getBundleName(), getRequest().getLocale(), classLoader);
	}

	/**
	 * Gets the text.
	 * 
	 * @param key
	 *            the key
	 * @return the text
	 */
	public String getErrorText(final String key) {
		String message;

		try {
			// message = getBundle().getString(key);
			message = getApplication().getResourceBundle(getFacesContext(), "error_message").getString(key);
		} catch (final java.util.MissingResourceException mre) {
			logger.warn("Missing key for '{}'", key);
			return "???" + key + "???";
		}

		return message;
	}

	public String getText(final String bundleName, final String key) {
		String message;
		try {
			message = getApplication().getResourceBundle(getFacesContext(), bundleName).getString(key);
		} catch (final java.util.MissingResourceException mre) {
			logger.warn("Missing key for '{}'", key);
			return "???" + key + "???";
		}

		return message;
	}

	/**
	 * Gets the text.
	 * 
	 * @param key
	 *            the key
	 * @param arg
	 *            the arg
	 * @return the text
	 */
	public String getErrorText(final String key, final Object arg) {
		if (arg == null) {
			return getErrorText(key);
		}

		final MessageFormat form = new MessageFormat(getApplication().getResourceBundle(getFacesContext(), "error_message").getString(key));

		if (arg instanceof String) {
			return form.format(new Object[] { arg });
		} else if (arg instanceof Object[]) {
			return form.format(arg);
		} else {
			logger.error("arg '{}' not String or Object[]", arg);

			return "";
		}
	}

	/**
	 * Adds the message.
	 * 
	 * @param key
	 *            the key
	 * @param arg
	 *            the arg
	 */
	@SuppressWarnings("unchecked")
	protected void addMessage(final String key, final Object arg) {
		List<String> messages = (List<String>) getSession().getAttribute("messages");

		if (messages == null) {
			messages = new ArrayList<String>();
		}

		messages.add(getErrorText(key, arg));
		getSession().setAttribute("messages", messages);
	}

	/**
	 * Adds the message.
	 * 
	 * @param key
	 *            the key
	 */
	protected void addMessage(final String key) {
		addMessage(key, null);
	}

	/**
	 * Adds the error.
	 * 
	 * @param key
	 *            the key
	 * @param arg
	 *            the arg
	 */
	@SuppressWarnings("unchecked")
	protected void addError(final String key, final Object arg) {
		List<String> errors = (List<String>) getSession().getAttribute("errors");

		if (errors == null) {
			errors = new ArrayList<String>();
		}

		// if key contains a space, don't look it up, it's likely a raw message
		if (key.contains(" ") && arg == null) {
			errors.add(key);
		} else {
			errors.add(getErrorText(key, arg));
		}

		getSession().setAttribute("errors", errors);
	}

	/**
	 * Adds the error.
	 * 
	 * @param key
	 *            the key
	 */
	protected void addError(final String key) {
		addError(key, null);
	}

	/**
	 * Convenience method for unit tests.
	 * 
	 * @return boolean indicator of an "errors" attribute in the session
	 */
	public boolean hasErrors() {
		return (getSession().getAttribute("errors") != null);
	}

	/**
	 * Servlet API Convenience method.
	 * 
	 * @return HttpServletRequest from the FacesContext
	 */
	protected HttpServletRequest getRequest() {
		return (HttpServletRequest) getFacesContext().getExternalContext().getRequest();
	}

	/**
	 * Servlet API Convenience method.
	 * 
	 * @return the current user's session
	 */
	protected HttpSession getSession() {
		return getRequest().getSession();
	}

	/**
	 * Servlet API Convenience method.
	 * 
	 * @return HttpServletResponse from the FacesContext
	 */
	protected HttpServletResponse getResponse() {
		return (HttpServletResponse) getFacesContext().getExternalContext().getResponse();
	}

	/**
	 * Servlet API Convenience method.
	 * 
	 * @return the ServletContext form the FacesContext
	 */
	protected ServletContext getServletContext() {
		return (ServletContext) getFacesContext().getExternalContext().getContext();
	}

	// The following methods are used by t:dataTable for sorting.
	/**
	 * Gets the sort column.
	 * 
	 * @return the sort column
	 */
	public String getSortColumn() {
		return sortColumn;
	}

	/**
	 * Sets the sort column.
	 * 
	 * @param sortColumn
	 *            the new sort column
	 */
	public void setSortColumn(final String sortColumn) {
		this.sortColumn = sortColumn;
	}

	/**
	 * Checks if is ascending.
	 * 
	 * @return true, if is ascending
	 */
	public Boolean getAscending() {
		return ascending;
	}

	/**
	 * Sets the ascending.
	 * 
	 * @param ascending
	 *            the new ascending
	 */
	public void setAscending(final Boolean ascending) {
		this.ascending = ascending;
	}

	/**
	 * Sort list according to which column has been clicked on.
	 * 
	 * @param list
	 *            the java.util.List to sort
	 * @return ordered list
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	protected List sort(final List list) {
		Comparator comparator = new BeanComparator(sortColumn, new NullComparator(nullsAreHigh));
		if (!ascending) {
			comparator = new ReverseComparator(comparator);
		}
		Collections.sort(list, comparator);
		return list;
	}

	/**
	 * Gets the theme.
	 * 
	 * @return the theme
	 */
	public String getTheme() {
		final Map<String, String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
		if (params.containsKey("theme")) {
			theme = params.get("theme");
		}

		return theme;
	}

	/**
	 * Sets the theme.
	 * 
	 * @param theme
	 *            the new theme
	 */
	public void setTheme(final String theme) {
		this.theme = theme;
	}
}
